/**
********************************************************************************
* @file     sdl_render.c
* @brief    对文件的简要说明
* @details  对文件的详细说明
* @author   jcai
* @date     2024-07-11 20:08:02
* @copyright Copyright &copy; 2024 wy1107412334@163.com All rights reserved
* @version  v0.0.1
*
* \n Email:  wy1107412334@163.com
* \n Blog:   None
* \n Github: https://github.com/wy1107412334
* \n Gitee:  https://gitee.com/git.git1107412334.com
*
********************************************************************************
* @note
* None.
********************************************************************************
* @attention
* None.
********************************************************************************
@verbatim
@endverbatim
********************************************************************************
* @par 历史记录
* jcai, 2024-07-11 20:08:02
* - 首次编写
*
*<center>Copyright &copy; 2024 wy1107412334@163.com All rights reserved</center>
********************************************************************************
*/

/* 头文件导入区 ------------------------------------------------------------- */

#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include "sdl_render.h"


/** @defgroup SDL_READER SDL_READER
* @brief sdl_reader modules
* @{
*/



/* 私有宏定义区 ------------------------------------------------------------- */

#define WIN_X_POS                               SDL_WINDOWPOS_CENTERED
#define WIN_Y_POS                               SDL_WINDOWPOS_CENTERED

#ifdef DEBUG
#define LOG(fmt, ...)   fprintf(stderr, "[%s:%s(%u)] " fmt "\n", \
        __FILE__, __func__, __LINE__, ##__VA_ARGS__)
#else
#define LOG(fmt, ...)
#endif
#define print(fmt, ...)   fprintf(stderr, "[%s:%s(%u)] " fmt "\n", \
        __FILE__, __func__, __LINE__, ##__VA_ARGS__)




/* 私有数据类型声明区 ------------------------------------------------------- */

typedef struct
{
    SL_NODE         node;
    SL_LIST         eventList;
    SDL_Window *    sdlwin;
    SDL_Renderer *  sdlrd;
    Uint8           rgba[4];
} sdl_win_info_t;





/* 私有变量定义区 ----------------------------------------------------------- */

static SL_LIST winList;
#ifdef EN_MOUSE
static SDL_Cursor * cursor; /* Make this variable visible in the point where you exit the program */
static uint32_t cursorData[8][2] = {{0, 0}};
#endif


/** @defgroup SDL_RENDER_Exported_Variables sdl_render exported variables
* @brief 全局变量定义
* @{
*/



/** defgroup SDL_RENDER_Exported_Variables
* @}
*/





/* 私有函数定义区 ----------------------------------------------------------- */

__attribute__((weak))
void lvgl_init(void)
{
}

__attribute__((weak))
void lvgl_loop(void)
{
}

__attribute__((weak))
void lvgl_deinit(void)
{
}

static void outSDLError(const char * msg)
{
    fprintf(stderr, "%s error: %s\n", msg, SDL_GetError());
}


static void win_destroy(void * node, int isDelNode)
{
    sdl_win_info_t * p = node;

    SDL_SetRenderDrawColor(p->sdlrd, p->rgba[0], p->rgba[1], p->rgba[2], p->rgba[3]);
    SDL_DestroyRenderer(p->sdlrd);
    SDL_DestroyWindow(p->sdlwin);
    if (isDelNode)
    {
        sllist_delete(&winList, &p->node);
        free(node);
    }
}

static uint32_t handle_all_window_event(const SDL_Event * e)
{
    uint32_t eventCnt = 0;

    SL_FOREACH(winNode, &winList)
    {
        sdl_win_info_t * pWin = (sdl_win_info_t *)winNode;
        SL_FOREACH(node, &pWin->eventList)
        {
            sdl_event_handle_arr_t * temp = (sdl_event_handle_arr_t *) node;
            sdl_event_handle_t * p = temp->arr;
            for (uint32_t i = 0; i < temp->arrlen; i++)
            {
                if (e->type == (p + i)->type)
                {
                    (p + i)->fn(e, temp->lvglDrv, (p + i)->arg);
                    eventCnt++;
                    break;
                }
            }
        }
    }
    return eventCnt;
}



/** @defgroup SDL_RENDER_Exported_Functions sdl_render exported functions
* @brief 全局函数定义
* @{
*/



/**
********************************************************************************
* @brief    简要说明
* @details  详细说明
* @param    none
* @param[in]     a: 该参数用于输入
* @param[in,out] b: 该参数用于输入和输出
* @param[out]    c: 该参数用于输出
* @retval  none
* @retval  0 函数成功
* @retval  1 函数失败
* @return  返回0成功；否则失败
* @note    none
*/

int sdl_init(void)
{
    if (SDL_Init(SDL_INIT_VIDEO) != 0)
    {
        outSDLError("SDL_Init()");
        return -1;
    }
    SLLIST_INIT(&winList);

    lvgl_init();

#ifdef EN_MOUSE
    cursor = SDL_CreateCursor((Uint8 *)cursorData, (Uint8 *)cursorData, 8, 8, 4, 4);
    if (cursor) SDL_SetCursor(cursor);
    else printf("cursor is NULL\n");
    SDL_ShowCursor(SDL_DISABLE);
#endif

    return 0;
}

void sdl_deinit(void)
{
    lvgl_deinit();

#ifdef EN_MOUSE
    if (cursor) SDL_FreeCursor(cursor);
#endif

    SL_FOREACH(node, &winList)
    {
        win_destroy(node, 0);
    }
    sllist_destroyCallback(&winList, (sl_trav_callback) free);
    SDL_Quit();
}


void * sdl_window_create(const char * title, uint32_t winWidth, uint32_t winHight)
{
    if ((!title) || (winWidth < 2) || (winHight < 2))   return NULL;

    sdl_win_info_t * p = malloc(sizeof(*p));
    if (p == NULL)  return NULL;

    p->sdlwin = SDL_CreateWindow(title, WIN_X_POS, WIN_Y_POS, winWidth, winHight, SDL_WINDOW_SHOWN);
    if (p->sdlwin == NULL)
    {
        outSDLError("SDL_CreateWindow()");
        goto initRet;
    }

    p->sdlrd = SDL_CreateRenderer(p->sdlwin, -1, SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC);
    if (p->sdlrd == NULL)
    {
        outSDLError("SDL_CreateRenderer()");
        goto winRet;
    }
    SDL_SetRenderDrawBlendMode(p->sdlrd, SDL_BLENDMODE_NONE);
    SDL_GetRenderDrawColor(p->sdlrd,
            &p->rgba[0], &p->rgba[1], &p->rgba[2], &p->rgba[3]);

    SLLIST_INIT(&p->eventList);
    sllist_insert_head(&winList, &p->node);

    return (void *) p;

winRet:
    SDL_DestroyWindow(p->sdlwin);
initRet:
    free(p);
    return NULL;
}

void sdl_window_destroy(void * handle)
{
    if (handle != NULL)
    {
        win_destroy(handle, 1);
    }
}

int sdl_event_listen(void * handle, sdl_event_handle_arr_t * eventArr)
{
    if ((!handle) || (!eventArr) || (!eventArr->arr) || (!eventArr->arrlen))
    {
        return -1;
    }

    sdl_win_info_t * p = handle;
    if (sllist_insert_head(&p->eventList, &eventArr->node) != 0)
    {
        return -1;
    }

    return 0;
}

void sdl_exec(void)
{
    int quit = 0;
    SDL_Event e;
    while (!quit)
    {
        while (SDL_PollEvent(&e))
        {
            uint32_t exist = 0;

            switch (e.type)
            {
            case SDL_QUIT:
                quit = 1;
                exist = 1;
                break;

            default:
                break;
            }
            
            exist |= handle_all_window_event(&e);

            if (!exist)
            {
                LOG("Unknown event: %#x", e.type);
            }
        }

        lvgl_loop();
    }
}


void sdl_draw_point(void * handle, uint32_t x, uint32_t y, uint8_t red, uint8_t green, uint8_t blue, uint8_t alpha)
{
    if (handle != NULL)
    {
        sdl_win_info_t * p = handle;
        SDL_SetRenderDrawColor(p->sdlrd, red, green, blue, alpha);
        SDL_RenderDrawPoint(p->sdlrd, x, y);
    }
}

void sdl_clear_screen(void * handle)
{
    if (handle != NULL)
    {
        sdl_win_info_t * p = handle;
        SDL_RenderClear(p->sdlrd);
    }
}

void sdl_update_screen(void * handle)
{
    if (handle != NULL)
    {
        sdl_win_info_t * p = handle;
        SDL_RenderPresent(p->sdlrd);
    }
}


/** defgroup SDL_RENDER_Exported_Functions
* @}
*/

/** defgroup SDL_RENDER
* @}
*/


/*********************************** END OF FILE ******************************/
